﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;

namespace Liquid.Collections {
	/// <summary>
	/// A set of extension methods that work on an <see cref="IChangeNotifyingEnumerable&lt;T&gt;" />
	/// </summary>
	public static partial class ChangeNotifyingEnumerable {
		/// <summary>
		/// Filters a sequence of values based on a predicate.
		/// </summary>
		/// <typeparam name="T">The type of the elements of source.</typeparam>
		/// <param name="source">An <see cref="IChangeNotifyingEnumerable&lt;T&gt;"/> to filter.</param>
		/// <param name="predicate">A function to test each element for a condition.</param>
		/// <returns></returns>
		public static IChangeNotifyingEnumerable<T> Where<T>(this IChangeNotifyingEnumerable<T> source, Func<T, bool> predicate) {
			return new FilterEnumerable<T>(source, predicate);
		}

		class FilterEnumerable<T> : IChangeNotifyingEnumerable<T> {
			IChangeNotifyingEnumerable<T> source;
			Func<T, bool> filter;

			public event ItemSetEventHandler<T> Added;
			public event ItemSetEventHandler<T> Removed;

			public FilterEnumerable(IChangeNotifyingEnumerable<T> source, Func<T, bool> filter) {
				this.source = source;
				source.Added += new ItemSetEventHandler<T>(source_Added);
				source.Removed += new ItemSetEventHandler<T>(source_Removed);
				this.filter = filter;
			}

			void source_Added(object sender, ItemSetEventArgs<T> e) {
				if (Added != null) {
					Added(this, new ItemSetEventArgs<T>(e.Items.Where(filter)));
				}
			}

			void source_Removed(object sender, ItemSetEventArgs<T> e) {
				if (Removed != null) {
					Removed(this, new ItemSetEventArgs<T>(e.Items.Where(filter)));
				}
			}

			public IEnumerator<T> GetEnumerator() {
				foreach (var item in source) {
					if (filter(item))
						yield return item;
				}
			}

			IEnumerator IEnumerable.GetEnumerator() {
				return this.GetEnumerator();
			}
		}
	}
}
